package com.heima.wemedia.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.heima.api.feign.ApArticleFeignClient;
import com.heima.audit.baidu.BaiduImageScan;
import com.heima.audit.baidu.BaiduTextScan;
import com.heima.audit.tess4j.Tess4jClient;
import com.heima.file.service.FileStorageService;
import com.heima.model.article.dtos.ArticleDto;
import com.heima.model.common.constants.WmNewsMessageConstants;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.wemedia.pojos.WmChannel;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.model.wemedia.pojos.WmUser;
import com.heima.wemedia.mapper.WmChannelMapper;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.mapper.WmUserMapper;
import com.heima.wemedia.service.WmProcessService;
import com.heima.wemedia.service.WmSensitiveService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * TODO
 *
 * @Author mr.wu
 * @Data #{DATE} #{TIME}
 */

@Service
@Slf4j
public class WmProcessServiceImpl implements WmProcessService {

    @Autowired
    private WmNewsMapper wmNewsMapper;
    @Autowired
    private ApArticleFeignClient apArticleFeignClient;
    @Autowired
    private WmUserMapper wmUserMapper;
    @Autowired
    private FileStorageService fileStorageService;
    @Autowired
    private BaiduTextScan baiduTextScan;
    @Autowired
    private BaiduImageScan baiduImageScan;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private WmChannelMapper wmChannelMapper;
    @Autowired
    private WmSensitiveService wmSensitiveService;
    @Autowired
    private Tess4jClient tess4jClient;


    @Override
    @Transactional
    @Async
    public void ProcessContent(Integer newsId) {
        List<Integer> status = new ArrayList<>();
        List<String> image = new ArrayList<>();
        WmNews wmNew = wmNewsMapper.selectById(newsId);
        String content = wmNew.getContent();
        // 获取 "content" 对应的 JSON 数组
        JSONArray contentArray = JSONArray.parseArray(content);
        String text = null;
        for (int i = 0; i < contentArray.size(); i++) {
            JSONObject itemObj = contentArray.getJSONObject(i);
            String type = itemObj.getString("type");
            if ("text".equals(type)) {
                text = itemObj.getString("value");
            } else if ("image".equals(type)) {
                String imageValue = itemObj.getString("value");
                image.add(imageValue);
            }
        }
        //光学字符识别（OCR）技术：Tess4j识别提取图片中的文本
        if (CollUtil.isNotEmpty(image)) {
            for (String x : image) {
                byte[] imageData = fileStorageService.downLoadFile(x);
                boolean d = doOCRTess4j(imageData, wmNew);
                if (!d) {
                    return;
                }
            }
        }

        //使用DAF算法对文本进行敏感词审核
        if(StrUtil.isNotBlank(text)){
            boolean b = wmSensitiveService.keySensitive(text);
            if (!b) {
                wmNew.setStatus((short) 2);
                wmNewsMapper.updateById(wmNew);
                return;
            }
        }

        if (StrUtil.isNotBlank(text)) {
            //根据BaiduTextScan类名获取textScan方法
            Integer i = baiduTextScan.textScan(text);
            if (i == 2) {
                status.add(i);
            }
            if (i == 3) {
                status.add(i);
            }
            if (i == 1) {
                status.add(i);
            }
            if (i == 4) {
                throw new RuntimeException("图片审核失败");
            }
        }

        if (CollUtil.isNotEmpty(image)) {
            image.forEach(x -> {
                //使用OCR技术Tess4j识别提取图片中的文本
                byte[] imageData = fileStorageService.downLoadFile(x);
                Integer i = baiduImageScan.imageScan(imageData);
                if (i == 2) {
                    status.add(i);
                } else if (i == 3) {
                    status.add(i);
                } else if (i == 1) {
                    status.add(i);
                } else {
                    throw new RuntimeException("图片审核失败");
                }
            });
        }
        // 检查是否有等于 2 的元素
        boolean containsTwo = status.stream().anyMatch(i -> i == 2);
        if (containsTwo) {
            wmNew.setStatus((short) 2);
        } else {
            boolean containsThree = status.stream().anyMatch(i -> i == 3);
            if (containsThree) {
                wmNew.setStatus((short) 3);
            } else {
                if (wmNew.getPublishTime() != null && wmNew.getPublishTime().after(new Date(System.currentTimeMillis()))) {
                    rabbitMqDelay(wmNew);
                } else {
                    wmNew.setStatus((short) 9);
                }
            }
        }

        if (wmNew.getStatus() == 9) {
            Long articleId = saveArticle(wmNew);
            wmNew.setArticleId(articleId);
        }
        wmNewsMapper.updateById(wmNew);
        log.info("审核已完成");
    }

    /**
     * 保存审核通过的文章
     *
     * @param wmNew
     */
    private Long saveArticle(WmNews wmNew) {
        ArticleDto dto = new ArticleDto();
        BeanUtils.copyProperties(wmNew, dto);
        dto.setAuthorId(Long.valueOf(wmNew.getUserId()));
        System.out.println(wmNew.getUserId());
        WmUser user = wmUserMapper.selectById(wmNew.getUserId());
        if (user == null) {
            throw new RuntimeException("该用户不存在");
        }
        dto.setAuthorName(user.getName());
        WmChannel wmChannel = wmChannelMapper.selectById(wmNew.getChannelId());
        if (wmChannel == null) {
            throw new RuntimeException("该频道不存在");
        }
        dto.setChannelName(wmChannel.getName());
        dto.setLayout(wmNew.getType());
        dto.setFlag((byte) 0);
        dto.setCreatedTime(new Date(System.currentTimeMillis()));
        if (wmNew.getType() == 3) {
            dto.setLayout((short) 2);
        }
        ResponseResult save = apArticleFeignClient.save(dto);
        Object data = save.getData();
        return Long.valueOf(String.valueOf(data));
    }

    /**
     * 发送延迟消息方法
     *
     * @param wmNew
     */
    private void rabbitMqDelay(WmNews wmNew) {
        wmNew.setStatus((short) 8);
        // 1.创建延迟消息
        Integer message = wmNew.getId();
        // 2.发送消息，利用消息后置处理器添加消息头
        rabbitTemplate.convertAndSend(WmNewsMessageConstants.DELAY_EXCHANGE_NAME, WmNewsMessageConstants.DELAY_ORDER_KEY, message, new MessagePostProcessor() {
            @Override
            public Message postProcessMessage(Message message) throws AmqpException {
                //计算延迟消息延迟的时间使用wmNew.getPublishTime()减去当前时间算出时间差单位为毫秒
                int delay = (int) (wmNew.getPublishTime().getTime() - System.currentTimeMillis());
                System.out.println(delay);
                // 添加延迟消息属性
                message.getMessageProperties().setDelay(delay);
                log.info("发送消息" + wmNew.getId() + LocalDateTime.now());
                return message;
            }
        });
    }

    /**
     * 使用光学字符识别（OCR）技术：Tess4j识别提取图片中的文本
     *
     * @param imageData
     * @param wmNew
     * @return
     */
    private boolean doOCRTess4j(byte[] imageData, WmNews wmNew) {

        try {
            BufferedImage bufferedImage = ImageIO.read(new ByteArrayInputStream(imageData));
            System.out.println(bufferedImage);
            String imageStr = tess4jClient.doOCR(bufferedImage);
            boolean result = wmSensitiveService.keySensitive(imageStr);
            if (!result) {
                wmNew.setStatus((short) 2);
                wmNewsMapper.updateById(wmNew);
                return false;
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return true;
    }
}
